package cn.com.netedge.iot.frontend.comm.nio;

import cn.com.netedge.iot.common.constants.CacheKeyConstants;
import cn.com.netedge.iot.common.dataobject.ReceiveFrame;
import cn.com.netedge.iot.common.enums.MessageDirectEnum;
import cn.com.netedge.iot.common.utils.DateUtil;
import cn.com.netedge.iot.common.utils.RedisUtil;
import cn.com.netedge.iot.common.utils.StringUtil;
import cn.com.netedge.iot.frontend.comm.constants.ChannelConstant;
import cn.com.netedge.iot.frontend.comm.utils.DecoderUtil;
import cn.com.netedge.iot.frontend.comm.utils.DeviceLogUtil;
import cn.com.netedge.iot.frontend.comm.utils.FeCommCacheUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.List;

public class MessageDecoder extends ByteToMessageDecoder {
    private static final Logger logger = LoggerFactory.getLogger(MessageDecoder.class);
    private static final int MAX_MESSAGE_COUNT = 60;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf inByteBuf, List<Object> out) throws Exception {
        String channelId = ctx.channel().id().asLongText();
        logger.debug("MessageDecoder decode channelId:{}", channelId);
        int bufSize = inByteBuf.readableBytes();
        logger.debug("buf size:{}", bufSize);

        ReceiveFrame frame = DecoderUtil.decode(ctx, inByteBuf);

        Date now = new Date();
        Date lastMinute = DateUtil.addMinutes(now, -1);
        String lastMinuteStr = DateUtil.DateToNosec10Str(lastMinute);
        byte[] data;
        boolean isNormalDevice = false, isIllegalDevice = false;
        String deviceNumber, notDocflag, messageCount, freezeFlag;
        int deviceType;

        while (frame != null) {
            deviceNumber = frame.getDeviceNumber();
            deviceType = frame.getDeviceType();
            data = frame.getRawData();
            if (StringUtil.isNotEmpty(deviceNumber)) {
                notDocflag = RedisUtil.get(CacheKeyConstants.KEY_DEVICE_NOT_EXISTS + deviceNumber + "_" + deviceType);
                //未建档 处理上报报文策略
                if (!StringUtil.isEmpty(notDocflag) && StringUtil.isDigits(notDocflag) && Integer.parseInt(notDocflag) > 0) {
                    logger.debug("deviceNumber:{} deviceType:{} not exist, message ignore...", deviceNumber, deviceType);
                    //记录异常报文日志
                    DeviceLogUtil.deviceLogger.logAbnormalMessage(deviceNumber, deviceType, MessageDirectEnum.UP, data);

                    isIllegalDevice = true;
                }
                if (!isIllegalDevice) {
                    messageCount = RedisUtil.get(CacheKeyConstants.KEY_DEVICE_MESSAGE_COUNT + deviceNumber + "_" + deviceType + "_" + lastMinuteStr);
                    if (!StringUtil.isEmpty(messageCount) && StringUtil.isDigits(messageCount) && Integer.parseInt(messageCount) >= MAX_MESSAGE_COUNT) {
                        logger.debug("{}'s message_count:{} exceed max_message_count:60, message ignore...", deviceNumber, messageCount);
                        //记录异常报文日志
                        DeviceLogUtil.deviceLogger.logAbnormalMessage(deviceNumber, deviceType, MessageDirectEnum.UP, data);

                        FeCommCacheUtil.setString(CacheKeyConstants.KEY_DEVICE_FREEZE_FLAG + deviceNumber, Boolean.TRUE.toString(), 60 * 5); //冻结5分钟
                        isIllegalDevice = true;
                    }

                    if (!isIllegalDevice) {
                        freezeFlag = RedisUtil.get(CacheKeyConstants.KEY_DEVICE_FREEZE_FLAG + deviceNumber);
                        if (!StringUtil.isEmpty(freezeFlag) && Boolean.TRUE.toString().equals(freezeFlag)) {
                            logger.debug("{} is in freeze mode, message ignore...", deviceNumber, messageCount);
                            //记录异常报文日志
                            DeviceLogUtil.deviceLogger.logAbnormalMessage(deviceNumber, deviceType, MessageDirectEnum.UP, data);
                            isIllegalDevice = true;
                        }
                    }
                }
            }

            isNormalDevice = true;
            data = frame.getRawData();
            out.add(frame);

            //记录报文日志
            DeviceLogUtil.deviceLogger.logMessage(frame.getDeviceNumber(), frame.getDeviceType(), MessageDirectEnum.UP, data);
            //移动bytebuf readIndex
            int readerIndex = frame.getReadIndex();
            int writeIndex = inByteBuf.writerIndex();
            if (readerIndex > writeIndex) {
                logger.debug("readIndex:{} > writeIndex:{} ", readerIndex, writeIndex);
                break;
            }
            inByteBuf.readerIndex(readerIndex);

            frame = DecoderUtil.decode(ctx, inByteBuf);
        }

        //移除已收到报文的通道，无需主动断开连接
        if (isNormalDevice && ChannelConstant.CHANNEL_CREATE_TIME_MAP.containsKey(channelId)) {
            ChannelConstant.CHANNEL_CREATE_TIME_MAP.remove(channelId);
        }
    }
}
